﻿using System;
using System.Text;
using System.Web;
using System.Net;
using System.Collections;
using System.Threading;

namespace FindDomains
{
    class DomainFetcher
    {
        public DomainFetcher(string IP)
        {
            if (!System.Net.IPAddress.TryParse(IP, out queryIpAddress))
            {
                try
                {
                    if (System.Net.Dns.GetHostEntry(IP).AddressList.Length > 0)
                        queryIpAddress = System.Net.Dns.GetHostEntry(IP).AddressList[0];
                }
                catch (System.Net.Sockets.SocketException se)
                {
                    Console.WriteLine(se.Message.ToString());
                    Console.WriteLine("--------------------");
                    return;
                }
            }
            int count = 0;
            Retry: 
            try
            {
                count++;
                total = FindDomains.WebSample.GetNumber(queryIpAddress.ToString());
            }
            catch (WebException we)
            {
                if (we.Status != WebExceptionStatus.ProtocolError && count <= 10)
                {
                    lock (this)
                    {
                        WebSample.timeout = WebSample.timeout + 2500;
                    }
                    goto Retry;
                }
                else
                    Console.WriteLine(we.ToString());
            }
            WebSample.timeout = 5000;
            uniqueHostNameList = new UniqueArrayList();
            threadCount = 20;
            Thread[] threadArray = new Thread[threadCount];

            request = FindDomains.WebSample.BuildRequest(queryIpAddress.ToString(), "0");
            try
            {
                for (int i = 0; i < threadCount; i++)
                    threadArray[i] = new Thread(new ParameterizedThreadStart(DownloadAndParse));
                
                for (int i = 0; i < threadCount; i++)
                    threadArray[i].Start(i * 50);

                for (int i = 0; i < threadCount; i++)
                    threadArray[i].Join();
                /* Downloading and parsing of search results are done*/
                threadCount = 10;

                for (int i = 0; i < threadCount; i++)
                    threadArray[i] = new Thread(new ParameterizedThreadStart(DNSResolveCheck));

                for (int i = 0; i < threadCount; i++)
                    threadArray[i].Start(Convert.ToInt32(System.Math.Ceiling(i * (uniqueHostNameList.Count / (threadCount*1.0)))));

                for (int i = 0; i < threadCount; i++)
                    threadArray[i].Join();

                foreach (string s in uniqueHostNameList)
                    Console.WriteLine(s.ToString());

                /* DNS Resolving operations are done.*/
            }
            catch (WebException ex)
            {
                // An exception occurred while accessing the network.
                Console.WriteLine(ex.Message);
            }
        }
        void DNSResolveCheck(Object threadIndex)
        {
            ArrayList tempUniqueList = new UniqueArrayList();
            tempUniqueList = (ArrayList)uniqueHostNameList.Clone();

            //elemination false-positives by DNS confirmation
            for (int i = (int)threadIndex; i <= (int)threadIndex + Convert.ToInt32(System.Math.Ceiling(i * (uniqueHostNameList.Count / (threadCount * 1.0)))); i++)
            {
                if (i >= tempUniqueList.Count || i < 0)
                    return;
                string s = tempUniqueList[i].ToString();
                string domain = s.Substring(s.IndexOf("://", 0) + 3).ToString();
                try
                {
                    bool myLock = false;
                    IPHostEntry ipHostEntry = new IPHostEntry();
                    ipHostEntry = System.Net.Dns.GetHostEntry(domain);
                    foreach (IPAddress ipAddress in ipHostEntry.AddressList)
                        if (ipAddress.ToString() == queryIpAddress.ToString())
                        {
                            myLock = true;
                            break;
                        }
                    if (!myLock)
                    {
                        lock (this)
                        {
                            uniqueHostNameList.Remove(s.ToString());
                        }
                    }

                }
                catch { }
            }
        }
        void DownloadAndParse(Object threadIndex)
        {
            int count = 0;
            if (((int)threadIndex >= total) || ((int)threadIndex < 0))
                return;
            Retry:
            try
            {
                count++;
                request = FindDomains.WebSample.BuildRequest(queryIpAddress.ToString(), ((int)threadIndex).ToString());
                // Send the request; display the response.
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                lock (this)
                {
                    uniqueHostNameList.addAll(WebSample.DisplayResponse(response));
                }
            }
            catch (WebException we)
            {
                if (we.Status != WebExceptionStatus.ProtocolError && count <= 3)
                {
                    if (count > 1)
                    {
                        lock (this)
                        {
                            WebSample.timeout = WebSample.timeout + 2500;
                        }
                    }
                    goto Retry;
                }
                else
                    Console.WriteLine(we.ToString());
            }
        }

        UniqueArrayList uniqueHostNameList;
        IPAddress queryIpAddress;
        int total;
        int threadCount;
        HttpWebRequest request;
    }
}
